package com.project.demo.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.project.demo.dao.UserFileMapper;
import com.project.demo.entity.User;
import com.project.demo.entity.UserFile;
import com.project.demo.service.UserFileService;
import com.project.demo.util.*;
import com.project.demo.service.UserService;

import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

@Service
public class UserFileServiceImpl implements UserFileService {
    @Resource
    private UserFileMapper userFileMapper;
    @Resource
    private TokenUtils tokenUtils;
    @Resource
    UserService service;

/*    @Override
    @SneakyThrows
    public Map<String, Object> add(MultipartFile multipartFile,String secretKey){
        // 创建一个临时文件
        Map<String,Object> map = new HashMap<>();
        File file = File.createTempFile("temp", null);
        try{
            // 将MultipartFile的内容写入临时文件
            multipartFile.transferTo(file);
            String fileName = multipartFile.getOriginalFilename();
            String filePath = "C:\\myFile" + File.separator + System.currentTimeMillis() + File.separator + fileName ;
            File fileOut = new File(filePath);
            validateAndCreateFile(fileOut);
            ABEEncryption.encryptFile(file,fileOut,secretKey);

            User user = tokenUtils.getUserIdByRequest();
            if(!ObjectUtils.isEmpty(user)){
                UserFile userFile = new UserFile();
                userFile.setUserId(user.getUserId());
                userFile.setUserName(user.getUsername());
                userFile.setFilePath(filePath);
                userFile.setFileName(fileName);
                userFile.setCreateTime(LocalDateTime.now());
                //计算源文件的
                List<String> originalBlockHashes = PDPDataIntegrityVerification.calculateBlockHashes(fileOut);
                String fileBlock = String.join(",", originalBlockHashes);
                userFile.setFileBlock(fileBlock);
                userFile.setStatus(0);
                userFileMapper.insert(userFile);
                map.put("result",true);
            } else {
                map.put("result",false);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            file.delete();
        }
        return map;
    }*/

    @Override
    @SneakyThrows
    public Map<String, Object> add(MultipartFile multipartFile,String secretKey){
        // 创建一个临时文件
        Map<String,Object> map = new HashMap<>();
//        File file = File.createTempFile("temp", null);
        try{
            // 将MultipartFile的内容写入临时文件
//            multipartFile.transferTo(file);
            String fileName = multipartFile.getOriginalFilename();
            String filePath = "C:\\myFile" + File.separator + System.currentTimeMillis() + File.separator + fileName ;
            File fileOut = new File(filePath);
            validateAndCreateFile(fileOut);
            // 将待加密文件中的数据读取data变量中
//            FileInputStream fileInputStream = new FileInputStream(file);
            InputStream inputStream = multipartFile.getInputStream();
            byte[] b = new byte[(int)  multipartFile.getSize()];  //定义文件大小的字节数据
            inputStream.read(b);//将文件数据存储在b数组
            String data = new String(b, StandardCharsets.UTF_8); //将字节数据转换为UTF-8编码的字符串
//            ABEEncryption.encryptFile(file,fileOut,secretKey);
            //加密文件
            User user = tokenUtils.getUserIdByRequest();
            SysKeyUtil.kemEncrypt(data,filePath);
            if(!ObjectUtils.isEmpty(user)){
                UserFile userFile = new UserFile();
                userFile.setUserId(user.getUserId());
                userFile.setUserName(user.getUsername());
                userFile.setFilePath(filePath);
                userFile.setFileName(fileName);
                userFile.setCreateTime(LocalDateTime.now());
                //计算源文件的
                List<String> originalBlockHashes = PDPDataIntegrityVerification.calculateBlockHashes(fileOut);
                String fileBlock = String.join(",", originalBlockHashes);
                userFile.setFileBlock(fileBlock);
                userFile.setStatus(0);
                userFileMapper.insert(userFile);
                map.put("result",true);
            } else {
                map.put("result",false);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
        }
        return map;
    }

    @Override
    public void download(HttpServletRequest request, HttpServletResponse response,String filePath,String fileName,String publicKey,String secretKey) {
//        downloadFile(request,response,filePath,fileName,publicKey,secretKey);
        Properties properties = JSONObject.parseObject(secretKey, Properties.class);
        try{
            String res = SysKeyUtil.kemDecrypt(filePath, properties);
            InputStream fis = new ByteArrayInputStream(res.getBytes(StandardCharsets.UTF_8));
            int FileSize = fis.available();
            byte[] buffer = new byte[FileSize];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            String agent = request.getHeader("USER-AGENT").toLowerCase();
            String filenameEncoder;
            if (agent.contains("msie")) {
                // IE浏览器
                filenameEncoder = URLEncoder.encode(fileName, "utf-8");
                filenameEncoder = filenameEncoder.replace("+", " ");
            } else if (agent.contains("firefox")) {
                // 火狐浏览器
                BASE64Encoder base64Encoder = new BASE64Encoder();
                filenameEncoder = "=?utf-8?B?" + base64Encoder.encode(fileName.getBytes(StandardCharsets.UTF_8)) + "?=";
            } else {
                // 其它浏览器
                filenameEncoder = URLEncoder.encode(fileName, "utf-8");
                filenameEncoder = filenameEncoder.replace("+", " ");
            }
            // 告诉客户端该文件不是直接解析，而是以附件形式打开（下载）
            response.setHeader("Content-Disposition", "attachment;filename=" + filenameEncoder);
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            toClient.write(buffer);
            toClient.flush();
            // 设置response的Header
            response.addHeader("Content-Length", String.valueOf(FileSize));
            response.setContentType("application/octet-stream");
            toClient.close();
        }catch (Exception e){
            System.out.println("下载失败"+e.getMessage());
            e.printStackTrace();
        }

    }

    private static void validateAndCreateFile(File file) throws Exception{
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
       file.createNewFile();
    }

    @Override
    public IPage<UserFile> pageList(UserFile userFile) {
        LambdaQueryWrapper<UserFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(!StringUtils.isEmpty(userFile.getUserName()),UserFile::getUserName,userFile.getUserName());
        return userFileMapper.selectPage(new Page<>(0,1),lambdaQueryWrapper);
    }



    @SneakyThrows
    public void downloadFile(HttpServletRequest request, HttpServletResponse response,String filePath,String fileName,String publicKey,String secretKey){
        //保存的文件路径
        try {
            File file = new File(filePath);
            File outfile = File.createTempFile("temp", null);
            if(EncryptionDecryption.encrypt(service.getSysKey()).equals(publicKey)){
                ABEEncryption.decryptFile(file,outfile,secretKey);
            }else{
                ABEEncryption.decryptFile(file,outfile,"1231231231231231");
            }
            // 以流的形式下载文件。
            InputStream fis = new BufferedInputStream(new FileInputStream(outfile));
            int FileSize = fis.available();
            byte[] buffer = new byte[FileSize];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            String agent = request.getHeader("USER-AGENT").toLowerCase();
            String filenameEncoder;
            if (agent.contains("msie")) {
                // IE浏览器
                filenameEncoder = URLEncoder.encode(fileName, "utf-8");
                filenameEncoder = filenameEncoder.replace("+", " ");
            } else if (agent.contains("firefox")) {
                // 火狐浏览器
                BASE64Encoder base64Encoder = new BASE64Encoder();
                filenameEncoder = "=?utf-8?B?" + base64Encoder.encode(fileName.getBytes(StandardCharsets.UTF_8)) + "?=";
            } else {
                // 其它浏览器
                filenameEncoder = URLEncoder.encode(fileName, "utf-8");
                filenameEncoder = filenameEncoder.replace("+", " ");
            }
            // 告诉客户端该文件不是直接解析，而是以附件形式打开（下载）
            response.setHeader("Content-Disposition", "attachment;filename=" + filenameEncoder);
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            toClient.write(buffer);
            toClient.flush();
            // 设置response的Header
            response.addHeader("Content-Length", String.valueOf(FileSize));
            response.setContentType("application/octet-stream");
            toClient.close();
            outfile.delete();
        } catch (FileNotFoundException e) {
            System.out.println("找不到附件");
        } catch (IOException e) {
            System.out.println("下载异常");
        }
    }

}
